import Watcher from "./observe/watcher"
import { patch } from "./patch"
import { createVElement, createVTextNode } from "./vdom/index"

export function initLifeCycle(Vue) {
  Vue.prototype._update = function (vnode) {
    // console.log(vnode)
    // 生成真实的dom元素
    const el = this.$el
    let preVnode = this._vnode
    this._vnode = vnode
    if (preVnode) {
      // 能拿到preVnode, 说明不是第一次渲染，此时传入虚拟节点进行diff算法比较
      this.$el = patch(preVnode, vnode)
    } else {
      this.$el = patch(el, vnode)
    }
  }
  // 创建vnode
  Vue.prototype._c = function (tag, attrs, ...children) {
    return createVElement(this, tag, attrs, ...children)
  }
  Vue.prototype._v = function (content) {
    return createVTextNode(this, content)
  }
  Vue.prototype._s = function (templateAttr) {
    if (typeof templateAttr === 'object') {
      templateAttr = JSON.stringify(templateAttr)
    }
    return templateAttr
  }
  Vue.prototype._render = function () {
    // console.log(this.$options.render)
    return this.$options.render.call(this)
  }
}

export function mountComponent(vm, el) {
  vm.$el = el

  // 通过_render方法生成虚拟节点，通过_update方法生成dom元素
  let updateComponent = function () { vm._update(vm._render()) }

  // 每个组件（视图）都有有个renderWatcher
  let watcher = new Watcher(vm, updateComponent, { renderWatcher: true })

  // console.log(watcher)
}

// Vue.核心流程
// 1. 创建了响应式数据
// 2. 模板转化为ast语法树
// 3. 根据ast语法树生成render函数
// 4. 根据render函数生成虚拟dom，此后渲染
// render函数的意义：ast正则匹配遍历所有的dom开销大，而使用render函数，每次更新响应式状态只需要重新执行render函数（无需再次执行ast转化）